#include <iostream>
#include <string>
#include <unistd.h>
#include <pthread.h>
using namespace std;

int tickets = 1000; // 有 1000 张票

// 需要定义在 threadRoutine 之前
class TData
{
public:
    TData(const string &name, pthread_mutex_t* pmtx)
        :_name(name), _pmtx(pmtx)
    {}

public:
    string _name;
    pthread_mutex_t* _pmtx;
};

void* threadRoutine(void* args)
{
    int sum = 0;
    TData* td = static_cast<TData*>(args); 
    while(true)
    {
        // 进入临界区，加锁
        pthread_mutex_lock(td->_pmtx);

        // 如果票数 > 0 才能抢
        if(tickets > 0)
        {
            usleep(2000); // 耗时 2ms
            sum++;
            tickets--;
            
            // 出临界区了，解锁
            pthread_mutex_unlock(td->_pmtx);
        }
        else
        {
            // 如果判断没有票了，也应该解锁
            pthread_mutex_unlock(td->_pmtx);
            break; // 没有票了
        }

        // 抢到票后还有后续动作
        usleep(2000); //抢到票后也需要时间处理
    }

    // 屏幕也是共享资源，加锁可以有效防止打印结果错行
    pthread_mutex_lock(td->_pmtx);
    cout << "线程 " << td->_name << " 抢票完毕，最终抢到的票数 " << sum << endl;
    pthread_mutex_unlock(td->_pmtx);

    delete td;
    return nullptr;
}

int main()
{
    // 创建一把锁
    pthread_mutex_t mtx;

    // 在线程创建前，初始化互斥锁
    pthread_mutex_init(&mtx, nullptr);

    pthread_t pt[5];
    for(int i = 0; i < 5; i++)
    {
        char* name = new char(16);
        snprintf(name, 16, "thread-%d", i);
        TData *td = new TData(name, &mtx);

        pthread_create(pt + i, nullptr, threadRoutine, td);
    }

    for(int i = 0; i < 5; i++)
        pthread_join(pt[i], nullptr);

    cout << "所有线程均已退出，剩余票数: " << tickets << endl;

    // 线程退出后，销毁互斥锁
    pthread_mutex_destroy(&mtx);

    return 0;
}
